home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / src / interp / perl-5.003.tar.gz / perl-5.003.tar / perl-5.003 / pod / pod2html.PL < prev    next >
Perl Script  |  1996-03-25  |  16KB  |  550 lines

  1. #!/usr/local/bin/perl
  2.  
  3. use Config;
  4. use File::Basename qw(&basename &dirname);
  5.  
  6. # List explicitly here the variables you want Configure to
  7. # generate.  Metaconfig only looks for shell variables, so you
  8. # have to mention them as if they were shell variables, not
  9. # %Config entries.  Thus you write
  10. #  $startperl
  11. # to ensure Configure will look for $Config{startperl}.
  12.  
  13. # This forces PL files to create target in same directory as PL file.
  14. # This is so that make depend always knows where to find PL derivatives.
  15. chdir(dirname($0));
  16. ($file = basename($0)) =~ s/\.PL$//;
  17. $file =~ s/\.pl$//
  18.     if ($^O eq 'VMS' or $^O eq 'os2');  # "case-forgiving"
  19.  
  20. open OUT,">$file" or die "Can't create $file: $!";
  21.  
  22. print "Extracting $file (with variable substitutions)\n";
  23.  
  24. # In this section, perl variables will be expanded during extraction.
  25. # You can use $Config{...} to use Configure variables.
  26.  
  27. print OUT <<"!GROK!THIS!";
  28. $Config{'startperl'}
  29. !GROK!THIS!
  30.  
  31. # In the following, perl variables are not expanded during extraction.
  32.  
  33. print OUT <<'!NO!SUBS!';
  34. eval 'exec perl -S $0 ${1+"$@"}'
  35.         if $running_under_some_shell;
  36. #
  37. # pod2html - convert pod format to html
  38. # Version 1.15
  39. # usage: pod2html [podfiles]
  40. # Will read the cwd and parse all files with .pod extension
  41. # if no arguments are given on the command line.
  42. #
  43. # Many helps, suggestions, and fixes from the perl5 porters, and all over.
  44. # Bill Middleton - wjm@metronet.com
  45. #
  46. # Please send patches/fixes/features to me
  47. #
  48. #
  49. *RS = */;
  50. *ERRNO = *!;
  51.  
  52. ################################################################################
  53. # Invoke with various levels of debugging possible
  54. ################################################################################
  55. while ($ARGV[0] =~ /^-d(.*)/) {
  56.     shift;
  57.     $Debug{ lc($1 || shift) }++;
  58. }
  59.  
  60. # ck for podnames on command line
  61. while ($ARGV[0]) {
  62.     push(@Pods,shift);
  63. }
  64.  
  65. ################################################################################
  66. # CONFIGURE
  67. #
  68. # The beginning of the url for the anchors to the other sections.
  69. # Edit $type to suit.  It's configured for relative url's now.
  70. # Other possibilities are:
  71. # $type = '<A HREF="file://localhost/usr/local/htmldir/'; # file url
  72. # $type = '<A HREF="http://www.bozo.com/perl/manual/html/' # server
  73. #
  74. ################################################################################
  75.  
  76. $type = '<A HREF="';        
  77. $dir = ".";             # location of pods
  78.  
  79. # look in these pods for things not found within the current pod
  80. # be careful tho, namespace collisions cause stupid links
  81.  
  82. @inclusions = qw[
  83.      perlfunc perlvar perlrun perlop 
  84. ];
  85. ################################################################################
  86. # END CONFIGURE
  87. ################################################################################
  88.  
  89. $A = {};  # The beginning of all things
  90.  
  91. unless (@Pods) {
  92.     opendir(DIR,$dir)  or  die "Can't opendir $dir: $ERRNO";
  93.     @Pods = grep(/\.pod$/,readdir(DIR));
  94.     closedir(DIR) or die "Can't closedir $dir: $ERRNO";
  95. }
  96. @Pods or die "aak, expected pods";
  97.  
  98. # loop twice through the pods, first to learn the links, then to produce html
  99. for $count (0,1) {
  100.     print STTDER "Scanning pods...\n" unless $count;
  101.     foreach $podfh ( @Pods ) {
  102.     ($pod = $podfh) =~ s/\.pod$//;
  103.     Debug("files", "opening 2 $podfh" );
  104.     print "Creating $pod.html from $podfh\n" if $count;
  105.     $RS = "\n=";         # grok pods by item (Nonstandard but effecient)
  106.     open($podfh,"<".$podfh)  || die "can't open $podfh: $ERRNO";
  107.     @all = <$podfh>;
  108.     close($podfh);
  109.     $RS = "\n";
  110.  
  111.     $all[0] =~ s/^=//;
  112.     for (@all) { s/=$// }
  113.     $Podnames{$pod} = 1;
  114.     $in_list = 0;
  115.     $html = $pod.".html";
  116.     if ($count) {              # give us a html and rcs header
  117.         open(HTML,">$html") || die "can't create $html: $ERRNO";
  118.         print HTML '<!-- $Id$ -->',"\n",'<HTML><HEAD>',"\n";
  119.         print HTML "<CENTER>" unless $NO_NS;
  120.         print HTML "<TITLE>$pod</TITLE>\n</HEAD>\n<BODY>";
  121.         print HTML "</CENTER>" unless $NO_NS;
  122.     }
  123.     for ($i = 0; $i <= $#all; $i++) {       # decide what to do with each chunk
  124.         $all[$i] =~ /^(\w+)\s*(.*)\n?([^\0]*)$/ ;
  125.         ($cmd, $title, $rest) = ($1,$2,$3);
  126.         if ($cmd eq "item") {
  127.         if ($count ) { # producing html
  128.             do_list("over",$all[$i],\$in_list,\$depth) unless $depth;
  129.             do_item($title,$rest,$in_list);
  130.         }
  131.         else {  
  132.             # scan item
  133.             scan_thing("item",$title,$pod);
  134.         }
  135.         }
  136.         elsif ($cmd =~ /^head([12])/) {
  137.         $num = $1;
  138.         if ($count) { # producing html
  139.             do_hdr($num,$title,$rest,$depth);
  140.         }
  141.         else {
  142.             # header scan
  143.             scan_thing($cmd,$title,$pod); # skip head1
  144.         }
  145.         }
  146.         elsif ($cmd =~ /^over/) {
  147.         $count and $depth and do_list("over",$all[$i+1],\$in_list,\$depth);
  148.         }
  149.         elsif ($cmd =~ /^back/) {
  150.         if ($count) {  # producing html
  151.             ($depth) or next; # just skip it
  152.             do_list("back",$all[$i+1],\$in_list,\$depth);
  153.             do_rest("$title.$rest");
  154.         }
  155.         }
  156.         elsif ($cmd =~ /^cut/) {
  157.         next;
  158.         }
  159.             elsif ($cmd =~ /^for/) {  # experimental pragma html
  160.                 if ($count) {  # producing html
  161.                     if ($title =~ s/^html//) {
  162.                         $in_html =1;
  163.                         do_rest("$title.$rest");
  164.                     }
  165.                 }
  166.             }
  167.             elsif ($cmd =~ /^begin/) {  # experimental pragma html
  168.                 if ($count) {  # producing html
  169.                     if ($title =~ s/^html//) {
  170.                         print HTML $title,"\n",$rest;
  171.                     }
  172.                     elsif ($title =~ /^end/) {
  173.                         next;
  174.                     }
  175.                 }
  176.             }
  177.         elsif ($Debug{"misc"}) { 
  178.         warn("unrecognized header: $cmd");
  179.         }
  180.     }
  181.         # close open lists without '=back' stmts
  182.     if ($count) {  # producing html
  183.         while ($depth) {
  184.          do_list("back",$all[$i+1],\$in_list,\$depth);
  185.         }
  186.         print HTML "\n</BODY>\n</HTML>\n";
  187.     }
  188.     }
  189. }
  190.  
  191. sub do_list{   # setup a list type, depending on some grok logic
  192.     my($which,$next_one,$list_type,$depth) = @_;
  193.     my($key);
  194.     if ($which eq "over") {
  195.     unless ($next_one =~ /^item\s+(.*)/) {
  196.         warn "Bad list, $1\n" if $Debug{"misc"};
  197.     }
  198.     $key = $1;
  199.  
  200.     if      ($key =~ /^1\.?/) {
  201.         $$list_type = "OL";
  202.     } elsif ($key =~ /\*\s*$/) {
  203.         $$list_type = "UL";
  204.     } elsif ($key =~ /\*?\s*\w/) {
  205.         $$list_type = "DL";
  206.     } else {
  207.         warn "unknown list type for item $key" if $Debug{"misc"};
  208.     }
  209.  
  210.     print HTML qq{\n};
  211.     print HTML $$list_type eq 'DL' ? qq{<DL COMPACT>} : qq{<$$list_type>};
  212.     $$depth++;
  213.     }
  214.     elsif ($which eq "back") {
  215.     print HTML qq{\n</$$list_type>\n};
  216.     $$depth--;
  217.     }
  218. }
  219.  
  220. sub do_hdr{   # headers
  221.     my($num,$title,$rest,$depth) = @_;
  222.     print HTML qq{<p><hr>\n} if $num == 1;
  223.     process_thing(\$title,"NAME");
  224.     print HTML qq{\n<H$num> };
  225.     print HTML $title; 
  226.     print HTML qq{</H$num>\n};
  227.     do_rest($rest);
  228. }
  229.  
  230. sub do_item{  # list items
  231.     my($title,$rest,$list_type) = @_;
  232.     my $bullet_only = $title eq '*' and $list_type eq 'UL';
  233.     process_thing(\$title,"NAME");
  234.     if ($list_type eq "DL") {
  235.     print HTML qq{\n<DT><STRONG>\n};
  236.     print HTML $title; 
  237.     print HTML qq{\n</STRONG>\n};
  238.     print HTML qq{<DD>\n};
  239.     }
  240.     else {
  241.     print HTML qq{\n<LI>};
  242.     unless ($bullet_only or $list_type eq "OL") {
  243.         print HTML $title,"\n";
  244.     }
  245.     }
  246.     do_rest($rest);
  247. }
  248.  
  249. sub do_rest{   # the rest of the chunk handled here
  250.     my($rest) = @_;
  251.     my(@lines,$p,$q,$line,,@paras,$inpre);
  252.     @paras = split(/\n\n\n*/,$rest);  
  253.     for ($p = 0; $p <= $#paras; $p++) {
  254.     $paras[$p] =~ s/^\n//mg;
  255.     @lines = split(/\n/,$paras[$p]);
  256.         if ($in_html) {  # handle =for html paragraphs
  257.             print HTML $paras[0];
  258.             $in_html = 0;
  259.             next;
  260.         }
  261.     elsif ($lines[0] =~ /^\s+\w*\t.*/) {  # listing or unordered list
  262.         print HTML qq{<UL>};
  263.         foreach $line (@lines) { 
  264.         ($line =~ /^\s+(\w*)\t(.*)/) && (($key,$rem) = ($1,$2));
  265.         print HTML defined($Podnames{$key}) 
  266.                 ?  "<LI>$type$key.html\">$key<\/A>\t$rem</LI>\n" 
  267.                 : "<LI>$line</LI>\n";
  268.         }
  269.         print HTML qq{</UL>\n};
  270.     }
  271.     elsif ($lines[0] =~ /^\s/) {       # preformatted code
  272.         if ($paras[$p] =~/>>|<</) {
  273.         print HTML qq{\n<PRE>\n};
  274.         $inpre=1;
  275.         }
  276.         else {                         # Still cant beat XMP.  Yes, I know 
  277.         print HTML qq{\n<XMP>\n}; # it's been obsoleted... suggestions?
  278.         $inpre = 0;
  279.         }
  280.         while (defined($paras[$p])) {
  281.             @lines = split(/\n/,$paras[$p]);
  282.         foreach $q (@lines) {      # mind your p's and q's here :-)
  283.             if ($paras[$p] =~ />>|<</) {
  284.             if ($inpre) {
  285.                 process_thing(\$q,"HTML");
  286.             }
  287.             else {
  288.                 print HTML qq{\n</XMP>\n};
  289.                 print HTML qq{<PRE>\n};
  290.                 $inpre=1;
  291.                 process_thing(\$q,"HTML");
  292.             }
  293.             }
  294.             1 while $q =~  s/\t+/' 'x (length($&) * 8 - length($`) % 8)/e;
  295.             print HTML  $q,"\n";
  296.         }
  297.         last if $paras[$p+1] !~ /^\s/;
  298.         $p++;
  299.         }
  300.         print HTML ($inpre==1) ? (qq{\n</PRE>\n}) : (qq{\n</XMP>\n});
  301.     }
  302.     else {                             # other text
  303.         @lines = split(/\n/,$paras[$p]);
  304.         foreach $line (@lines) {
  305.                 process_thing(\$line,"HTML");
  306.         print HTML qq{$line\n};
  307.         }
  308.     }
  309.     print HTML qq{<p>};
  310.     }
  311. }
  312.  
  313. sub process_thing{       # process a chunk, order important
  314.     my($thing,$htype) = @_;
  315.     pre_escapes($thing);
  316.     find_refs($thing,$htype);
  317.     post_escapes($thing);
  318. }
  319.  
  320. sub scan_thing{           # scan a chunk for later references
  321.     my($cmd,$title,$pod) = @_;
  322.     $_ = $title;
  323.     s/\n$//;
  324.     s/E<(.*?)>/&$1;/g;
  325.     # remove any formatting information for the headers
  326.     s/[SFCBI]<(.*?)>/$1/g;         
  327.     # the "don't format me" thing
  328.     s/Z<>//g;
  329.     if ($cmd eq "item") {
  330.         /^\*/ and  return;     # skip bullets
  331.         /^\d+\./ and  return;     # skip numbers
  332.         s/(-[a-z]).*/$1/i;
  333.     trim($_);
  334.         return if defined $A->{$pod}->{"Items"}->{$_};
  335.         $A->{$pod}->{"Items"}->{$_} = gensym($pod, $_);
  336.         $A->{$pod}->{"Items"}->{(split(' ',$_))[0]}=$A->{$pod}->{"Items"}->{$_};
  337.         Debug("items", "item $_");
  338.         if (!/^-\w$/ && /([%\$\@\w]+)/ && $1 ne $_ 
  339.             && !defined($A->{$pod}->{"Items"}->{$_}) && ($_ ne $1)) 
  340.         {
  341.             $A->{$pod}->{"Items"}->{$1} = $A->{$pod}->{"Items"}->{$_};
  342.             Debug("items", "item $1 REF TO $_");
  343.         } 
  344.         if ( m{^(tr|y|s|m|q[qwx])/.*[^/]} ) {
  345.             my $pf = $1 . '//';
  346.             $pf .= "/" if $1 eq "tr" || $1 eq "y" || $1 eq "s";
  347.             if ($pf ne $_) {
  348.                 $A->{$pod}->{"Items"}->{$pf} = $A->{$pod}->{"Items"}->{$_};
  349.                 Debug("items", "item $pf REF TO $_");
  350.             }
  351.     }
  352.     }
  353.     elsif ($cmd =~ /^head[12]/) {                
  354.         return if defined($A->{$pod}->{"Headers"}->{$_});
  355.         $A->{$pod}->{"Headers"}->{$_} = gensym($pod, $_);
  356.         Debug("headers", "header $_");
  357.     } 
  358.     else {
  359.         warn "unrecognized header: $cmd" if $Debug;
  360.     } 
  361. }
  362.  
  363.  
  364. sub picrefs { 
  365.     my($char, $bigkey, $lilkey,$htype) = @_;
  366.     my($key,$ref,$podname);
  367.     for $podname ($pod,@inclusions) {
  368.     for $ref ( "Items", "Headers" ) {
  369.         if (defined $A->{$podname}->{$ref}->{$bigkey}) {
  370.         $value = $A->{$podname}->{$ref}->{$key = $bigkey};
  371.         Debug("subs", "bigkey is $bigkey, value is $value\n");
  372.         } 
  373.         elsif (defined $A->{$podname}->{$ref}->{$lilkey}) {
  374.         $value = $A->{$podname}->{$ref}->{$key = $lilkey};
  375.         return "" if $lilkey eq '';
  376.         Debug("subs", "lilkey is $lilkey, value is $value\n");
  377.         } 
  378.     } 
  379.     if (length($key)) {
  380.             ($pod2,$num) = split(/_/,$value,2);
  381.         if ($htype eq "NAME") {  
  382.         return "\n<A NAME=\"".$value."\">\n$bigkey</A>\n"
  383.         }
  384.         else {
  385.         return "\n$type$pod2.html\#".$value."\">$bigkey<\/A>\n";
  386.         }
  387.     } 
  388.     }
  389.     if ($char =~ /[IF]/) {
  390.     return "<EM>$bigkey</EM>";
  391.     } elsif ($char =~ /C/) {
  392.     return "<CODE>$bigkey</CODE>";
  393.     } else {
  394.     return "<STRONG>$bigkey</STRONG>";
  395.     }
  396.  
  397. sub find_refs { 
  398.     my($thing,$htype) = @_;
  399.     my($orig) = $$thing;
  400.     # LREF: a manpage(3f) we don't know about
  401.     for ($$thing) {
  402.     #s:L<([a-zA-Z][^\s\/]+)(\([^\)]+\))>:the I<$1>$2 manpage:g;
  403.         s@(\S+?://\S*[^.,;!?\s])@noremap(qq{<A HREF="$1">$1</A>})@ge;
  404.         s,([a-z0-9_.-]+\@([a-z0-9_-]+\.)+([a-z0-9_-]+)),noremap(qq{<A HREF="MAILTO:$1">$1</A>}),gie;
  405.     s/L<([^>]*)>/lrefs($1,$htype)/ge;
  406.     s/([CIBF])<(\W*?(-?\w*).*?)>/picrefs($1, $2, $3, $htype)/ge;
  407.     s/(S)<([^\/]\W*?(-?\w*).*?)>/picrefs($1, $2, $3, $htype)/ge;
  408.     s/((\w+)\(\))/picrefs("I", $1, $2,$htype)/ge;
  409.     s/([\$\@%](?!&[gl]t)([\w:]+|\W\b))/varrefs($1,$htype)/ge;
  410.     }
  411.     if ($$thing eq $orig && $htype eq "NAME") { 
  412.     $$thing = picrefs("I", $$thing, "", $htype);
  413.     }
  414.  
  415. }
  416.  
  417. sub lrefs {
  418.     my($page, $item) = split(m#/#, $_[0], 2);
  419.     my($htype) = $_[1];
  420.     my($podname);
  421.     my($section) = $page =~ /\((.*)\)/;
  422.     my $selfref;
  423.     if ($page =~ /^[A-Z]/ && $item) {
  424.     $selfref++;
  425.     $item = "$page/$item";
  426.     $page = $pod;
  427.     }  elsif (!$item && $page =~ /[^a-z\-]/ && $page !~ /^\$.$/) {
  428.     $selfref++;
  429.     $item = $page;
  430.     $page = $pod;
  431.     } 
  432.     $item =~ s/\(\)$//;
  433.     if (!$item) {
  434.         if (!defined $section && defined $Podnames{$page}) {
  435.         return "\n$type$page.html\">\nthe <EM>$page</EM> manpage<\/A>\n";
  436.     } else {
  437.         (warn "Bizarre entry $page/$item") if $Debug;
  438.         return "the <EM>$_[0]</EM>  manpage\n";
  439.     } 
  440.     } 
  441.  
  442.     if ($item =~ s/"(.*)"/$1/ || ($item =~ /[^\w\/\-]/ && $item !~ /^\$.$/)) {
  443.     $text = "<EM>$item</EM>";
  444.     $ref = "Headers";
  445.     } else {
  446.     $text = "<EM>$item</EM>";
  447.     $ref = "Items";
  448.     } 
  449.     for $podname ($pod, @inclusions) {
  450.     undef $value;
  451.     if ($ref eq "Items") {
  452.         if (defined($value = $A->{$podname}->{$ref}->{$item})) {
  453.         ($pod2,$num) = split(/_/,$value,2);
  454.         return (($pod eq $pod2) && ($htype eq "NAME"))
  455.             ? "\n<A NAME=\"".$value."\">\n$text</A>\n"
  456.             : "\n$type$pod2.html\#".$value."\">$text<\/A>\n";
  457.             }
  458.         } 
  459.     elsif ($ref eq "Headers") {
  460.         if (defined($value = $A->{$podname}->{$ref}->{$item})) {
  461.         ($pod2,$num) = split(/_/,$value,2);
  462.         return (($pod eq $pod2) && ($htype eq "NAME")) 
  463.             ? "\n<A NAME=\"".$value."\">\n$text</A>\n"
  464.             : "\n$type$pod2.html\#".$value."\">$text<\/A>\n";
  465.             }
  466.     }
  467.     }
  468.     warn "No $ref reference for $item (@_)" if $Debug;
  469.     return $text;
  470.  
  471. sub varrefs {
  472.     my ($var,$htype) = @_;
  473.     for $podname ($pod,@inclusions) {
  474.     if ($value = $A->{$podname}->{"Items"}->{$var}) {
  475.         ($pod2,$num) = split(/_/,$value,2);
  476.         Debug("vars", "way cool -- var ref on $var");
  477.         return (($pod eq $pod2) && ($htype eq "NAME"))  # INHERIT $_, $pod
  478.         ? "\n<A NAME=\"".$value."\">\n$var</A>\n"
  479.         : "\n$type$pod2.html\#".$value."\">$var<\/A>\n";
  480.     }
  481.     }
  482.     Debug( "vars", "bummer, $var not a var");
  483.     return "<STRONG>$var</STRONG>";
  484.  
  485. sub gensym {
  486.     my ($podname, $key) = @_;
  487.     $key =~ s/\s.*//;
  488.     ($key = lc($key)) =~ tr/a-z/_/cs;
  489.     my $name = "${podname}_${key}_0";
  490.     $name =~ s/__/_/g;
  491.     while ($sawsym{$name}++) {
  492.         $name =~ s/_?(\d+)$/'_' . ($1 + 1)/e;
  493.     }
  494.     return $name;
  495.  
  496. sub pre_escapes {  # twiddle these, and stay up late  :-)
  497.     my($thing) = @_;
  498.     for ($$thing) { 
  499.     s/"(.*?)"/``$1''/gs;
  500.     s/&/noremap("&")/ge;
  501.     s/<</noremap("<<")/eg;
  502.     s/([^ESIBLCF])</$1\<\;/g;
  503.     s/E<([^\/][^<>]*)>/\&$1\;/g;              # embedded special
  504.     }
  505. }
  506. sub noremap {   # adding translator for hibit chars soon
  507.     my $hide = $_[0];
  508.     $hide =~ tr/\000-\177/\200-\377/;  
  509.     $hide;
  510.  
  511.  
  512. sub post_escapes {
  513.     my($thing) = @_;
  514.     for ($$thing) {
  515.     s/([^GM])>>/$1\>\;\>\;/g;
  516.     s/([^D][^"MGA])>/$1\>\;/g;
  517.     tr/\200-\377/\000-\177/;
  518.     }
  519. }
  520.  
  521. sub Debug {
  522.     my $level = shift;
  523.     print STDERR @_,"\n" if $Debug{$level};
  524.  
  525. sub dumptable  {
  526.     my $t = shift;
  527.     print STDERR "TABLE DUMP $t\n";
  528.     foreach $k (sort keys %$t) {
  529.     printf STDERR "%-20s <%s>\n", $t->{$k}, $k;
  530.     } 
  531. sub trim {
  532.     for (@_) {
  533.         s/^\s+//;
  534.         s/\s\n?$//;
  535.     }
  536. }
  537. !NO!SUBS!
  538.  
  539. close OUT or die "Can't close $file: $!";
  540. chmod 0755, $file or die "Can't reset permissions for $file: $!\n";
  541. exec("$Config{'eunicefix'} $file") if $Config{'eunicefix'} ne ':';
  542.